/*
** listener.c -- a datagram sockets "server" demo
*/

#include "udps.h"
#include "data.h"
#include <ctime>
#include <memory.h>
#include <qtmetamacros.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <udp.h>
#ifdef _MSWIN_
#include <windows.h>
#include <winsock2.h>
#else
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#endif

#define MAXBUFLEN 512

#define UDP_ADDR "127.0.0.1"
#define UDP_PORT "34567"

static int sockfd = 0;

void*
udp_main(void* param)
{
  struct addrinfo hints, *servinfo, *p;
  int rv;
  int numbytes;
  struct sockaddr_storage their_addr;
  char buf[MAXBUFLEN];
  socklen_t addr_len;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_INET; // set to AF_INET to use IPv4
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_flags = AI_PASSIVE; // use my IP

  if ((rv = getaddrinfo(UDP_ADDR, UDP_PORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return nullptr;
  }

  // loop through all the results and bind to the first we can
  for (p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
      perror("listener: socket");
      continue;
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
      close(sockfd);
      perror("listener: bind");
      continue;
    }

    break;
  }

  if (p == NULL) {
    freeaddrinfo(servinfo);
    fprintf(stderr, "listener: failed to bind socket\n");
    return (void*)(-1); // return int
  }

  freeaddrinfo(servinfo);

  addr_len = sizeof their_addr;
  while ((numbytes = recvfrom(sockfd,
                              buf,
                              MAXBUFLEN - 1,
                              0,
                              (struct sockaddr*)&their_addr,
                              &addr_len)) != -1) {
    buf[numbytes] = '\0';
    if (!strcmp(buf, "quit-app")) {
      break;
    } else {
      parse_data(buf);
    }
  }

  close(sockfd);
  sockfd = 0;

  pthread_exit(NULL);
  return NULL;
}

UdpClient* g_uc = nullptr;

void
close_udp_server()
{
  g_uc = init_udp_client(UDP_ADDR, UDP_PORT);

  if (!g_uc)
    return;

  udpc_send_message(g_uc, "quit-app");
  close_udp_client(g_uc);
}
